﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Runtime.ExceptionServices;
using System.Security;
using System.Text;

namespace huqiang.Communication
{
    public class KcpLink : NetworkLink
    {
        public class KcpDataPacker : DataPacker
        {
            KcpLink kcpLink;
            public KcpDataPacker(KcpLink link2)
            {
                kcpLink = link2;
            }
            public override void FirstSend(byte[] dat, int start, int len)
            {
                kcpLink.kcp.soc.SendTo(dat, start, len, SocketFlags.None, kcpLink.endPoint);
            }
            public override void Dispatch(byte[] buf, int start, int len)
            {
                kcpLink.Dispatch(buf, start, len);
            }
        }
        internal KcpListener kcp;
        public string uniId;
        public byte[] Key;
        public byte[] Iv;
        public bool AllowFileTransfer;
        public KcpDataPacker dataPacker;

        /// <summary>
        /// 最后一次接受到数据的时钟周期
        /// </summary>
        public long RecvTime;
        /// <summary>
        /// 5秒
        /// </summary>
        public static long TimeOut = 50000000;//5*1000*10000
        /// <summary>
        /// 消息超时重传时间默认 500毫秒
        /// </summary>
        public int MsgTimeOut = 500;
        /// <summary>
        /// 第一次连接时间
        /// </summary>
        public long ConnectTime;
        /// <summary>
        /// 最后一次接收到数据的时间
        /// </summary>
        protected long lastTime;
        public KcpLink()
        {
            maxDataSize = 32 * DataPacker.FragmentDataSize;
            dataPacker = new KcpDataPacker(this);
        }
        public virtual void Awake()
        {
        }
        /// <summary>
        /// 注意此函数为分线程调用，UI线程请使用线程任务委托
        /// </summary>
        public virtual void Connect()
        {
        }
        public void Redirect(int ciP, int cport)
        {
            endPoint.Address = new IPAddress(ciP.ToBytes());
            endPoint.Port = cport;
            ip = ciP;
            port = cport;
            dataPacker.Clear();
        }
        public void Redirect(string cip, int cport)
        {
            endPoint.Address = IPAddress.Parse(cip);
            endPoint.Port = cport;
            unsafe
            {
                byte[] buf = endPoint.Address.GetAddressBytes();
                ip = buf.ReadInt32(0);
            }
            port = cport;
            dataPacker.Clear();
        }
        public virtual void Dispatch(byte[] buf, int start, int len)
        {
        }
        internal void ResendTimeOut(Socket soc, long time)
        {
            //int ac = 0;
            int c = 0;
            int all = 0;
            int s = 0;
            var sendBuffer = dataPacker.sendBuffer;
            for (int i = 0; i < sendBuffer.Count; i++)
            {
                unsafe
                {
                    fixed (byte* bp = &sendBuffer[i][0])
                    {
                        DataPacker.MsgSendCache* mp = (DataPacker.MsgSendCache*)bp;
                        long os = time - mp->SendTime;
                        if (os >= MsgTimeOut)
                        {
                            int len = mp->Len;
                            mp->SendTime = time;
                            mp->SendCount++;
                            byte* vp = bp + DataPacker.MsgSendCache.Size;
                            for (int j = 0; j < len; j++)
                            {
                                DataPacker.maxBuffer[s] = vp[j];
                                s++;
                            }
                            all += len;
                            c++;
                            if (c >= 32)
                            {
                                try
                                {
                                    soc.SendTo(DataPacker.maxBuffer, 0, all, SocketFlags.None, endPoint);
                                }
                                catch { }

                                c = 0;
                                all = 0;
                                s = 0;
                            }
                        }
                    }
                }
            }
            for (int i = 0; i < dataPacker.broadcastMsg.Max; i++)//发送广播消息
            {
                long os = time - dataPacker.broadcastMsg.msgs[i].SendTime;
                if (os >= MsgTimeOut)
                {
                    int len = dataPacker.broadcastMsg.msgs[i].dataLen;
                    dataPacker.broadcastMsg.msgs[i].SendTime = time;
                    dataPacker.broadcastMsg.msgs[i].SendCount++;
                    for (int j = 0; j < len; j++)
                    {
                        DataPacker.maxBuffer[s] = dataPacker.broadcastMsg.msgs[i].data[j];
                        s++;
                    }
                    all += len;
                    c++;
                    if (c >= 32)
                    {
                        try
                        {
                            soc.SendTo(DataPacker.maxBuffer, 0, all, SocketFlags.None, endPoint);
                        }
                        catch { }

                        c = 0;
                        all = 0;
                        s = 0;
                    }
                }
            }
            if (all > 0)
            {
                soc.SendTo(DataPacker.maxBuffer, 0, all, SocketFlags.None, endPoint);
            }
            //if (ac > 0)
            //    Console.WriteLine(ac);
        }

        /// 持续发送，用于比较大的数据
        /// </summary>
        public virtual void ContinuousSend()
        {

        }
        NetworkContent nc;
        internal void HandleSendStack(UInt16 time)
        {
            int c = ncStack.Count;
            for (int i = 0; i < c; i++)
            {
                if (dataPacker.Remain > 32)
                {
                    if (ncStack.Dequeue(ref nc))
                    {
                        if (nc.dat != null)
                        {
                            dataPacker.AddSendMsg(nc.dat, time);
                        }
                    }
                    else break;
                }
                else break;
            }
        }
        /// <summary>
        /// 返回true,则在线程管理中移除,不再参与重连
        /// </summary>
        /// <returns></returns>
        public virtual bool Disconnect()
        {
            dataPacker.Clear();
            _connect = false;
            return true;
        }
        public void AddRecvMsg(byte[] buf, int len)
        {
            for (int i = 0; i < len; i++)
            {
                RecvBuffer[RecvLen] = buf[i];
                RecvLen++;
                if (RecvLen >= 65536)
                    break;
            }
        }
        public virtual void Clear()
        {
            dataPacker.Clear();
        }
        public override void Dispose()
        {
            dataPacker.Clear();
        }
    }
}